/*
 * Copyright (C) 2012 DataSymphony (http://datasymphony.com.au)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package au.com.ds.restty.js;

import java.util.Collection;
import java.util.Date;
import java.util.Map;

import org.mozilla.javascript.Function;
import org.mozilla.javascript.IdScriptableObject;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;

import au.com.ds.restty.exc.JavaScriptError;


public class JsObjectFactory {	
	private JsObjectFactory(){}
	
	public static JsAnyObject create(Object o){
		// create simple objects
		if (o == null){
			return getJsNull();
		}
		
		if (o instanceof Integer){
			return getJsDouble((Integer) o);
		}
		
		if (o instanceof Double){
			return getJsDouble((Double) o);
		}
		
		if (o instanceof String){
			return getJsString((String) o);
		}
		
		if (o instanceof Boolean){
			return getJsBoolean((Boolean) o);
		}
				
		if (o instanceof Undefined){
			return getJsUndefined();
		}
		
		// create date
		if (o instanceof IdScriptableObject){
			IdScriptableObject so = (IdScriptableObject) o;
			if (so.getClassName().equals("Date")){
				Double time = (Double) ScriptableObject.callMethod(so, "getTime", null);
				return getJsDate(new Date(time.longValue()));
			}
		}
		
		// create array
		if (o instanceof NativeArray){
			NativeArray na = (NativeArray) o;
			JsArray a = getJsArray();
			
			for (int i = 0; i < na.getLength(); i++){
				Object oo = na.get(i, null);
				a.put(create(oo));
			}
			return a;
		}
		
		// create object
		if (o instanceof NativeObject){
			NativeObject no = (NativeObject) o;
			JsObject jo = getJsObject();
			
			for (Object k : no.getIds()){
				Object v = null;
				if (k instanceof Integer) {
					v = no.get((Integer) k, null);
				} else {
					v = no.get(k.toString(), null);
				}
				
				jo.put(create(k), create(v));
			}
			
			return jo;
		}
		
		// create function
		if (o instanceof Function){
			JsFunction f = new JsFunction((Function) o);
			return f;
		}		
		
		throw new JavaScriptError("Unsupported object: " + o.getClass());
	}

	public static JsArray getJsArray(){
		return new JsArray();
	}

	public static JsArray getJsArray(Collection<JsAnyObject> col){
		return new JsArray(col);
	}
	
	public static JsDouble getJsDouble(double val){
		return new JsDouble(val);
	}
	
	public static JsBoolean getJsBoolean(boolean val){
		return new JsBoolean(val);
	}
	
	public static JsDate getJsDate(Date val){
		return new JsDate(val);
	}
	
	public static JsNull getJsNull(){
		return JsNull.INSTANCE;
	}
	
	public static JsObject getJsObject(){
		return new JsObject();
	}
	
	public static JsObject getJsObject(Map<JsAnyObject, JsAnyObject> map){
		return new JsObject(map);
	}
	
	public static JsString getJsString(String val){
		return new JsString(val);
	}
	
	public static JsUndefined getJsUndefined(){
		return JsUndefined.INSTANCE;
	}
}
